package com.yunban.project.api.text_check.utils;

import com.alibaba.fastjson2.JSON;
import com.yunban.project.api.text_check.domain.CorrectionConfig;
import com.yunban.project.api.text_check.enums.CorrectionModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: lijiajun
 * @date: 2024-11-25
 * @version: 1.0
 */
@Slf4j
public class TextCorrectMatch {


    public static void main(String[] args) {
        String text1 = "16个月建造一艘7500车位双燃料汽车滚装船，全国首部折叠渐进式实景演艺带来500多场震撼体验，福州数字经济企业开拓人工智能、条码检测“新大陆”……18日，中央网信办网络社会工作局、中国互联网发展基金会、省委网信办联合举办的2025年“高质量发展中国行”系列专题活动暨首站“智造福建”走访考察活动在你你你福州启动。中中央、省市重点新闻单位记者和网络大V深入连江、马尾，走访船厂、景区、企业等，感受福州高质量发展新动能。";
        String text2 = "";

        CorrectionConfig config = new CorrectionConfig();
        config.setCode(CorrectionModel.BAIDU_AI);
        config.setName("baidu");

        List<TextCorrectionMatchResp> differences = obscureCompareTextsV2(config, text1, text2, null, null, "x");
        System.out.println(JSON.toJSONString(differences));
    }


    // TODO  lijiajun  2025-03-13   在 obscureCompareTexts 函数中，使用originalText.indexOf()函数计算开始位置下标，有点问题，因为一个句子中会出现重复的字词，这样会导致下标错误，所以需要定义两个句子的偏移量来处理这个逻辑
    public static List<TextCorrectionMatchResp> obscureCompareTextsV2(CorrectionConfig correctConfig, String originalText, String correctedText, String category, String source, String level) {
        if (originalText == null || correctedText == null) {
            return new ArrayList<>();
        }
        // 如果 error-text 里的错误内容和纠错后的内容相同，那么则需要删除掉 error-text 标签
        correctedText = handleErrorText(correctedText);
        List<TextCorrectionMatchResp> diffList = new ArrayList<>();

        // 如果原始文本或纠正文本以<br/>结尾，则删除<br/>
        if (originalText.endsWith("<br/>")) {
            originalText = originalText.substring(0, originalText.length() - 5);
        }
        if (correctedText.endsWith("<br/>")) {
            correctedText = correctedText.substring(0, correctedText.length() - 5);
        }

        // 分割原始文本和纠正文本为句子列表
        List<String> originalSentences = splitIntoSentences(originalText);
        List<String> correctedSentences = splitIntoSentences(correctedText);

        if (originalSentences.size() != correctedSentences.size()) {
            if (originalText.equals(correctedText)) {
                return new ArrayList<>();
            }
            char lastChar = originalText.charAt(originalText.length() - 1);
            char corrChar = correctedText.charAt(correctedText.length() - 1);
            int endIndex = originalText.length() - 1;
            System.out.println("originalText:" + originalText);
            System.out.println("correctedText:" + correctedText);
            if (!isDelimiter(lastChar) && isDelimiter(corrChar)) {
                endIndex = endIndex + 1;
            }
            log.info("原始文本和纠正文本长度不一致，无法进行精确匹配。");
            diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), source, 0, endIndex, originalText, correctedText, LocalDateTime.now(), category, 0, level));
            log.info("原始文本和纠正文本长度不一致，无法进行精确匹配 DIFF:{}", JSON.toJSONString(diffList));
            log.info("originalSentences:{}", JSON.toJSONString(originalSentences));
            log.info("correctedSentences:{}", JSON.toJSONString(correctedSentences));
            return diffList;
        }

        int originalOffset = 0; // 累计偏移量，用于追踪原始文本中的当前位置
        int correctedOffset = 0; // 累计偏移量，用于追踪纠正文本中的当前位置

        int i = 0, j = 0;
        while (i < originalSentences.size() && j < correctedSentences.size()) {
            String origSentence = originalSentences.get(i);
            String corrSentence = correctedSentences.get(j);

            if (!origSentence.equals(corrSentence)) {
                // 使用累计偏移量来计算差异部分的开始和结束位置
                int startIndex = originalOffset;
                int endIndex = startIndex + origSentence.length() - 1;

                // 处理 <br/> 标签
                if (origSentence.contains("<br/>") && corrSentence.contains("<br/>")) {
                    origSentence = origSentence.replaceAll("<br/>", "");
                    corrSentence = corrSentence.replaceAll("<br/>", "");
                    endIndex = endIndex - 4; // 减去 <br/> 的长度（假设是 5 个字符）
                } else if (origSentence.contains("<br/>") && !corrSentence.contains("<br/>")) {
                    origSentence = origSentence.replaceAll("<br/>", "");
                    endIndex = endIndex - 4;
                } else if (corrSentence.contains("<br/>") && !origSentence.contains("<br/>")) {
                    corrSentence = corrSentence.replaceAll("<br/>", "");
                }

                if (origSentence.contains("<br/>") || corrSentence.contains("<br/>")) {
                    log.error("<br/> 错误");
                    log.info("origSentence:{}", origSentence);
                    log.info("corrSentence:{}", corrSentence);
                }
                // 如果原句字最后一个字符不是 标点，并且纠错后的句子后面是标点，那么则需要进行 endIndex +1
                // 取出 原句字 最后一个字符
                char lastChar = origSentence.charAt(origSentence.length() - 1);
                char corrChar = corrSentence.charAt(corrSentence.length() - 1);
                if (!isDelimiter(lastChar) && isDelimiter(corrChar)) {
                    endIndex = endIndex + 1;
                }
                // 添加到差异集合
                diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), source, startIndex, endIndex, origSentence, corrSentence, LocalDateTime.now(), category, 0, level));
            }

            // 更新累计偏移量
            originalOffset += originalSentences.get(i).length();
            correctedOffset += correctedSentences.get(j).length();

            // 移动指针
            i++;
            j++;
        }

        System.out.println(JSON.toJSONString(diffList));

        // 处理 correctedText 最后多余的句子
        while (j < correctedSentences.size()) {
            String extraSentence = correctedSentences.get(j);
            diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), source, originalText.length(), originalText.length() - 1, "", extraSentence, LocalDateTime.now(), category, 0, level));
            j++;
        }

        // 合并相邻的差异
//        mergeAdjacentDifferences(diffList);

        if (!CollectionUtils.isEmpty(diffList)) {
            log.info("aaa diffList:{}", JSON.toJSONString(diffList));
        }

        return diffList;
    }


    /**
     * 获取文本差异
     *
     * @param correctConfig 纠错模型配置
     * @param originalText  错误的文本
     * @param correctedText 正确的文本
     * @return 文本差异比对响应
     * @description 模糊匹配，匹配到了错误词的句子的位置
     */
    public static List<TextCorrectionMatchResp> obscureCompareTexts(CorrectionConfig correctConfig, String originalText, String correctedText, String category, String source, String level) {
        if (originalText == null || correctedText == null) {
            return new ArrayList<>();
        }
        List<TextCorrectionMatchResp> diffList = new ArrayList<>();
        if (originalText.endsWith("<br/>")) {
            originalText = originalText.substring(0, originalText.length() - 5);
        }
        if (correctedText.endsWith("<br/>")) {
            correctedText = correctedText.substring(0, correctedText.length() - 5);
        }
        // 分割原始文本和纠正文本为句子列表
        List<String> originalSentences = splitIntoSentences(originalText);
        List<String> correctedSentences = splitIntoSentences(correctedText);
        if (originalSentences.size() != correctedSentences.size()) {
            if (originalText.equals(correctedText)) {
                return new ArrayList<>();
            }
            log.info("原始文本和纠正文本长度不一致，无法进行精确匹配。");
            // 如果 originalText 是 <br/> 结尾，那么则删除掉br
            if (originalText.endsWith("<br/>")) {
                originalText = originalText.substring(0, originalText.length() - 5);
            }
            char lastChar = originalText.charAt(originalText.length() - 1);
            char corrChar = correctedText.charAt(correctedText.length() - 1);
            int endIndex = originalText.length() - 1;
            System.out.println("originalText:" + originalText);
            System.out.println("correctedText:" + correctedText);
            if (!isDelimiter(lastChar) && isDelimiter(corrChar)) {
                endIndex = endIndex + 1;
            }
            diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), source, 0, endIndex, originalText, correctedText, LocalDateTime.now(), category, 0, level));
            log.info("原始文本和纠正文本长度不一致，无法进行精确匹配 DIFF:{}", JSON.toJSONString(diffList));
            log.info("originalSentences:{}", JSON.toJSONString(originalSentences));
            log.info("correctedSentences:{}", JSON.toJSONString(correctedSentences));
            return diffList;
        }
        int i = 0, j = 0;
        while (i < originalSentences.size() && j < correctedSentences.size()) {
            String origSentence = originalSentences.get(i);
            String corrSentence = correctedSentences.get(j);
//            System.out.println(origSentence);
            if (!origSentence.equals(corrSentence)) {
                // 找到差异的部分
                int startIndex = originalText.indexOf(origSentence, i == 0 ? 0 : originalText.indexOf(originalSentences.get(i - 1)) + originalSentences.get(i - 1).length());

                int endIndex = startIndex + origSentence.length() - 1;

                if (origSentence.contains("<br/>") && corrSentence.contains("<br/>")) {
                    origSentence = origSentence.replaceAll("<br/>", "");
                    corrSentence = corrSentence.replaceAll("<br/>", "");
                    // 需要减去 <br/> length + \n length  = 1
                    endIndex = endIndex - 4;
                }
                if (origSentence.contains("<br/>") && !corrSentence.contains("<br/>")) {
                    origSentence = origSentence.replaceAll("<br/>", "");
                    endIndex = endIndex - 4;
                }

                if (corrSentence.contains("<br/>") && !origSentence.contains("<br/>")) {
                    corrSentence = corrSentence.replaceAll("<br/>", "");
                }

                if (origSentence.contains("<br/>") || corrSentence.contains("<br/>")) {
                    log.error("<br/> 错误");
                    log.info("origSentence:{}", origSentence);
                    log.info("corrSentence:{}", corrSentence);
                }
                // 如果原句字最后一个字符不是 标点，并且纠错后的句子后面是标点，那么则需要进行 endIndex +1
                // 取出 原句字 最后一个字符
                char lastChar = origSentence.charAt(origSentence.length() - 1);
                char corrChar = corrSentence.charAt(corrSentence.length() - 1);
                if (!isDelimiter(lastChar) && isDelimiter(corrChar)) {
                    endIndex = endIndex + 1;
                }

                // 添加到差异集合
                diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), source, startIndex, endIndex, origSentence, corrSentence, LocalDateTime.now(), category, 0, level));
            }
            // 移动指针
            i++;
            j++;
        }

        System.out.println(JSON.toJSONString(diffList));
        // 处理 correctedText 最后多余的句子
        while (j < correctedSentences.size()) {
            String extraSentence = correctedSentences.get(j);
            diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), source, originalText.length(), originalText.length() - 1, "", extraSentence, LocalDateTime.now(), category, 0, level));
            j++;
        }
        // 合并相邻的差异
        mergeAdjacentDifferences(diffList);
        if (!CollectionUtils.isEmpty(diffList)) {
            log.info("aaa diffList:{}", JSON.toJSONString(diffList));
        }
        return diffList;
    }

    private static List<String> splitIntoSentences(String text) {
        List<String> sentences = new ArrayList<>();
        StringBuilder sentence = new StringBuilder();
        for (int k = 0; k < text.length(); k++) {
            char c = text.charAt(k);
            sentence.append(c);
            if (isDelimiter(c)) {
                sentences.add(sentence.toString().trim());
                // 清空StringBuilder
                sentence.setLength(0);
            }
        }
        if (!sentence.isEmpty()) {
            sentences.add(sentence.toString().trim());
        }
        return sentences;
    }

    public static boolean isDelimiter(char c) {
//        return c == '。' || c == '，' || c == '；' || c == '！' || c == '？' || c == ',' || c == '?' || c == '!' || c == ';';
        return c == '。' || c == '；' || c == '！' || c == '？' || c == '?' || c == '!' || c == ';';
//        return false;
    }

    private static void mergeAdjacentDifferences(List<TextCorrectionMatchResp> diffList) {
        List<TextCorrectionMatchResp> mergedDiffList = new ArrayList<>();
        for (int i = 0; i < diffList.size(); i++) {
            TextCorrectionMatchResp currentDiff = diffList.get(i);
            if (i > 0) {
                TextCorrectionMatchResp prevDiff = mergedDiffList.get(mergedDiffList.size() - 1);
                if (currentDiff.getErrorStartIndex() == prevDiff.getErrorEndIndex() + 1) {
                    // 合并相邻的差异
                    prevDiff.setErrorEndIndex(currentDiff.getErrorEndIndex());
                    prevDiff.setErrorText(prevDiff.getErrorText() + currentDiff.getErrorText());
                    prevDiff.setCorrectText(prevDiff.getCorrectText() + currentDiff.getCorrectText());
                    continue;
                }
            }
            mergedDiffList.add(currentDiff);
        }
        diffList.clear();
        diffList.addAll(mergedDiffList);
    }


    /**
     * 获取文本差异
     *
     * @param originalText  错误的文本
     * @param correctedText 正确的文本
     * @return 文本差异比对响应
     */
    public static List<TextCorrectionMatchResp> compareTexts(CorrectionConfig correctConfig, String originalText, String correctedText) {
        if (!StringUtils.hasText(originalText) || !StringUtils.hasText(correctedText)) {
            return new ArrayList<>();
        }
        int m = originalText.length();
        int n = correctedText.length();

        // 动态规划计算LCS
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (originalText.charAt(i - 1) == correctedText.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // 回溯找出LCS
        StringBuilder lcs = new StringBuilder();
        int i = m, j = n;
        while (i > 0 && j > 0) {
            if (originalText.charAt(i - 1) == correctedText.charAt(j - 1)) {
                lcs.append(originalText.charAt(i - 1));
                i--;
                j--;
            } else if (dp[i - 1][j] >= dp[i][j - 1]) {
                i--;
            } else {
                j--;
            }
        }
        lcs.reverse();

        // 找出差异部分
        List<TextCorrectionMatchResp> diffList = new ArrayList<>();
        i = 0;
        j = 0;
        int k = 0;
        while (i < m || j < n) {
            if (i < m && j < n && originalText.charAt(i) == correctedText.charAt(j)) {
                i++;
                j++;
                k++;
            } else {
                int start = i;
                StringBuilder errorText = new StringBuilder();
                StringBuilder correctText = new StringBuilder();
                while (i < m && (k >= lcs.length() || originalText.charAt(i) != lcs.charAt(k))) {
                    errorText.append(originalText.charAt(i));
                    i++;
                }
                while (j < n && (k >= lcs.length() || correctedText.charAt(j) != lcs.charAt(k))) {
                    correctText.append(correctedText.charAt(j));
                    j++;
                }
                k++;
                diffList.add(new TextCorrectionMatchResp(correctConfig.getCode(), correctConfig.getName(), null, start, i, errorText.toString(), correctText.toString(), LocalDateTime.now(), null, 0, "x"));
            }
        }
        return diffList;
    }

    // 处理errorText 相同字符串

    /**
     * text = 最后还是轻轻抽出了两只<error-text :绿豆冰棍>绿豆冰棍</error-text><error-text :>。</error-text>
     * 如果  <error-text :绿豆冰棍>绿豆冰棍</error-text> 这个标签内容相同的话，那么则认为是无效数据，需要将标签去掉
     *
     * @param text 文本
     * @return String
     */
    public static String handleErrorText(String text) {
//        String text = "最后还是轻轻抽出了两只<error-text :绿豆冰棍>绿豆冰棍</error-text><error-text :>。</error-text>";
        // 使用正则表达式匹配 <error-text> 标签及其内容
        String regex = "<error-text\\s*:\\s*([^>]*?)>(.*?)</error-text>";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        // 用于存储已经遇到的内容
        StringBuilder result = new StringBuilder();
        int lastEnd = 0;
        while (matcher.find()) {
            // 先将上次匹配结束到这次匹配开始之间的文本（即未被标签包裹的部分）添加到结果中
            result.append(text, lastEnd, matcher.start());
            // 获取标签内的内容（冒号后的部分）
            String tagContent = matcher.group(1).trim();
            // 获取标签内的文本
            String innerContent = matcher.group(2).trim();

            // 如果标签内容和内部文本不同，则保留该标签
            if (!tagContent.equals(innerContent)) {
                // 添加整个匹配的标签
                result.append(matcher.group());
            } else {
                result.append(innerContent);
            }
            lastEnd = matcher.end();
        }
        // 最后添加从最后一次匹配结束到字符串末尾的部分（即未被标签包裹的部分）
        result.append(text.substring(lastEnd));
        return result.toString();
    }

//    public static void main(String[] args) {
//        String text = "最后还是轻轻抽出了两只<error-text :绿豆冰棍></error-text><error-text :>。</error-text>";
//        System.out.println(handleErrorText(text));
//    }
}